/**
 * 
 */
package stc.skymobi.cli;

import java.io.ByteArrayOutputStream;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.StringTokenizer;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

/**
 * @author Marvin.Ma
 *
 */
public class CommandShell<CTX extends CliContext> {
	
	private	CTX					commandContext;
	
	private	String				wordDelim = " ";
	
	
	public String execute(final String cmdline) {
		
		try {
			final StringBuilder sb = new StringBuilder();
			final JSONArray cmds = JSON.parseArray(cmdline);
			
			//	json 格式命令输入
			final Iterator<Object> itr = cmds.iterator();
			
			while ( itr.hasNext() ) {
				final JSONObject cmdarg = (JSONObject)itr.next();
				if ( null != cmdarg ) {
					final String cmdname = cmdarg.getString("command");

					if ( null != cmdname ) {
						sb.append(execute(cmdname, cmdarg) + "\r\n");
					}
					else {
						sb.append("failed: can not find command attr for json: " + cmdarg.toJSONString() + "\r\n");
					}
				}
			}
			return	sb.toString();
		}
		catch (Exception e) {
			//	非json 格式命令输入
		}
		
		final List<String> words = new ArrayList<String>();
		final StringTokenizer	st = new StringTokenizer(cmdline, wordDelim, false);
		while (st.hasMoreTokens()) {
			words.add( st.nextToken().trim() );
		}
		if ( words.isEmpty() ) {
			return "failed: cmdline is empty";
		}
		
		return execute(words.toArray(new String[0]));
	}

	public String execute(final String[] cmds) {
		if ( null == cmds || cmds.length == 0 ) {
			return "failed: cmdline is empty";
		}
		
		final String action = cmds[0];
		
		final CliCommand<CTX> cmd = 
			commandContext.getCommandRepository().findCommandByAction(action);
		
		if ( null == cmd ) {
			return "failed: can not find [" + action + "] command";
		}
		
		try {
			return cmd.execute(Arrays.copyOfRange(cmds, 1, cmds.length), 
					commandContext);
		}
		catch( Exception e) {
			return exception2detail(e);
		}
	}

	public String execute(final String action, final JSONObject arg) {
		if ( null == action ) {
			return "failed: cmdline is empty";
		}
		
		final CliCommand<CTX> cmd = 
			commandContext.getCommandRepository().findCommandByAction(action);
		
		if ( null == cmd ) {
			return "failed: can not find [" + action + "] command";
		}
		
		if ( cmd instanceof JSONCommand ) {
			try {
				return ((JSONCommand)cmd).execute(arg, commandContext);
			}
			catch(Exception e) {
				return exception2detail(e);
			}
		}
		else {
			return	"failed: cmd [" + action + "] not impl JSONCommand Interface.";
		}
	}
	
	/**
	 * @param e
	 * @return
	 */
	private String exception2detail(Exception e) {
		final ByteArrayOutputStream os = new ByteArrayOutputStream();
		final PrintWriter writer = new PrintWriter(os);
		e.printStackTrace(writer);
		writer.flush();
		
		try {
			return "failed: catch exception [" + os.toString("UTF-8") + "]";
		} catch (UnsupportedEncodingException e1) {
			e1.printStackTrace();
			return "failed: catch exception [" + e + "]";
		}
	}
	
	/**
	 * @return the commandContext
	 */
	public CTX getCommandContext() {
		return commandContext;
	}

	/**
	 * @param commandContext the commandContext to set
	 */
	public void setCommandContext(CTX commandContext) {
		this.commandContext = commandContext;
	}

	/**
	 * @return the wordDelim
	 */
	public String getWordDelim() {
		return wordDelim;
	}

	/**
	 * @param wordDelim the wordDelim to set
	 */
	public void setWordDelim(String wordDelim) {
		this.wordDelim = wordDelim;
	}
}
